package model

import (
	. "github.com/klen-ygs/gorm-zero/gormc/sql"
	"gorm.io/gorm"
	"fmt"
	"errors"
	"context"
	"github.com/klen-ygs/gorm-zero/gormc"
)

// avoid unused err
var _ = InitField
var _ UtxoModel = (*customUtxoModel)(nil)

type (
	// UtxoModel is an interface to be customized, add more methods here,
	// and implement the added methods in customUtxoModel.
	UtxoModel interface {
		utxoModel
		customUtxoLogicModel
	}

	customUtxoLogicModel interface {
		WithSession(tx *gorm.DB) UtxoModel
		Search(ctx context.Context, limit int, offset int) ([]Utxo, int32, error)
		UserAddMoney(uid int64, money int64, detail string) error
		UserDelMoney(uid int64, money int64, detail string) error
	}

	customUtxoModel struct {
		*defaultUtxoModel
	}
)

func (c customUtxoModel) WithSession(tx *gorm.DB) UtxoModel {
	newModel := *c.defaultUtxoModel
	c.defaultUtxoModel = &newModel
	c.conn = tx
	return c
}

func (c customUtxoModel) UserAddMoney(uid int64, money int64, detail string) error {
	// 开始事务
	tx := c.conn.Begin()
	var user Moneys
	if err := tx.First(&user, uid).Error; err != nil {
		tx.Rollback()
		fmt.Println("Failed to lock the row in table Moneys")
		return err
	}
	billing := true
	utxo := Utxo{
			Money       : money,
			Detail      : detail,
			Billingtype : &billing,
			Uid         : user.Id,
			Uuid        : user.Uuid,
			Types       : user.Types,
		}
	if err := tx.Create(&utxo).Error; err != nil {
		tx.Rollback()
		fmt.Println("Failed to insert record in table Utxo")
		return err
	}
	user.Money += money
	if err := tx.Save(&user).Error; err != nil {
		tx.Rollback()
		fmt.Println("Failed to update record in table Moneys")
		return err
	}
	if err := tx.Commit().Error; err != nil {
		tx.Rollback()
		fmt.Println("Transaction failed:", err)
		return err
	}
	return nil
}

func (c customUtxoModel) UserDelMoney(uid int64, money int64, detail string) error {
	// 开始事务
	tx := c.conn.Begin()
	var user Moneys
	if err := tx.First(&user, uid).Error; err != nil {
		tx.Rollback()
		fmt.Println("Failed to lock the row in table Moneys")
		return err
	}
	if user.Money < money {
		tx.Rollback()
		return errors.New("余额不足")
	}
	billing := false
	utxo := Utxo{
			Money       : money,
			Detail      : detail,
			Billingtype : &billing,
			Uid         : user.Id,
			Uuid        : user.Uuid,
			Types       : user.Types,
		}
	if err := tx.Create(&utxo).Error; err != nil {
		tx.Rollback()
		fmt.Println("Failed to insert record in table Utxo")
		return err
	}
	user.Money -= money
	if err := tx.Save(&user).Error; err != nil {
		tx.Rollback()
		fmt.Println("Failed to update record in table Moneys")
		return err
	}
	if err := tx.Commit().Error; err != nil {
		tx.Rollback()
		fmt.Println("Transaction failed:", err)
		return err
	}
	return nil
}

// NewUtxoModel returns a model for the database table.
func NewUtxoModel(conn *gorm.DB) UtxoModel {
	return &customUtxoModel{
		defaultUtxoModel: newUtxoModel(conn),
	}
}

func (m *defaultUtxoModel) customCacheKeys(data *Utxo) []string {
	if data == nil {
		return []string{}
	}
	return []string{}
}

func (m *defaultUtxoModel) Search(ctx context.Context, limit int, offset int) ([]Utxo, int32, error) {
	var resp []Utxo
	var count int64
	filter := Utxo{
				Removed:false,
			}
	err := m.conn.WithContext(ctx).Model(&Utxo{}).Where(&filter).Count(&count).Offset(offset).Limit(limit).Find(&resp).Error
	// err := m.conn.WithContext(ctx).Model(&Utxo{}).Count(&count).Offset(offset).Limit(limit).Take(&resp).Error
	if err == gormc.ErrNotFound {
		return nil, 0, err
	}
	return resp, int32(count), err
}